use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use axum::{Extension, extract::{Json, Path, Query, Request}, Form};
use axum::body::Bytes;
use axum::extract::State;
use axum::http::StatusCode;
use axum::response::{Html, Response};
use sea_orm::{ConnectionTrait, DatabaseBackend, DatabaseConnection, QueryResult, Statement};
use sea_orm::prelude::Uuid;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::user;

/// 官方提取器文档： https://docs.rs/axum/latest/axum/extract/index.html


/// 项目路由请求处理器
// 响应类型为固定静态字符串的处理程序
pub async fn root() -> &'static str {
    "Hello, World!"
}
// 响应类型为 Html 网页文档的处理程序
pub async fn html() -> Html<&'static str> {
    Html("<h1>Welcome to the root endpoint!</h1>")
}



/// Extractors 执行器，提取器是你如何分离传入请求以获取处理程序所需的部分
// 从 URL 路径中提取参数，其中 T 是路径参数的类型。例如，Path<i32> 可以从路径 /users/123 中提取数字 123
pub async fn path(Path(user_id): Path<u32>) -> ApiResponse<u32> {
    // Path路径，eg. /users/<id>
    println!("User ID: {}", user_id);
    ApiResponse::new(StatusCode::OK.as_u16(), StatusCode::OK.to_string(), Some(user_id))
}

// 从查询字符串中提取参数，其中 T 是一个实现了 FromQuery trait 的类型。例如，Query<MyQueryParams> 可以从 ?page=1&limit=10 中提取页面和限制参数
pub async fn query(Query(params): Query<HashMap<String, String>>) -> ApiResponse<HashMap<String, String>> {
    // Query查询参数，eg. /users?page=1&per_page=30
    println!("Params: {:?}", params);
    ApiResponse::new(StatusCode::OK.as_u16(), StatusCode::OK.to_string(), Some(params))
}

// 从请求体中读取 JSON 格式的数据并将其解码为 T 类型，此处为 Value 类型
pub async fn json(Json(payload): Json<Value>) -> ApiResponse<Value> {
    // 请求体 JSON，eg. {"username": "John Doe"}
    println!("Payload: {:?}", payload);
    ApiResponse::new(StatusCode::OK.as_u16(), StatusCode::OK.to_string(), Some(payload))
}

// 从请求中提取共享数据，如数据库连接、应用程序状态等
#[derive(Clone, Debug)]
pub struct AppState {
    db: DatabaseConnection,
}

// 序共享状态提取器
pub async fn state(State(state): State<AppState>) {
    // 使用 state.db 或 state.config
    let db = state.db;
    // 执行原始SQL查询
    let query_res: Option<QueryResult> = db
        .query_one(Statement::from_string(
            DatabaseBackend::MySql,
            "SELECT * FROM `xxl_job_user`;",
        ))
        .await.unwrap();
    let data = query_res.unwrap();
    println!("the data is {:?}", data);
}

// 可以将上面的 Value 类型换成自定义的结构体类型
pub async fn create_user (Json(payload): Json<user::Model>) -> ApiResponse<user::Model> {
    // 判断请求体数据是否有效
    // if let Some(payload) = payload {
    //     // We got a valid JSON payload
    //     println!("We got a valid JSON payload: {:?}", payload);
    // } else {
    //     // Payload wasn't valid JSON
    //     println!(" Payload wasn't valid JSON");
    // }

    // 在此处插入应用程序逻辑
    let user = user::Model {
        user_id: Uuid::new_v4().to_string(),
        name: payload.name,
        password: "".to_string(),
        ..Default::default()
    };
    // Json(user) 将 user 转换为 JSON 格式响应
    println!("Create User: {:?}", Json(&user));
    ApiResponse::new(StatusCode::OK.as_u16(), StatusCode::OK.to_string(), Some(user))
}

#[derive(Deserialize)]
struct MyFormData {
    email: String,
    password: String,
}
// 从请求体中读取表单编码的数据并将其解码为 T 类型，此处为 MyFormData 类型
async fn post_form(Form(form): Form<MyFormData>) -> String {
    format!("Email: {}, Password: {}", form.email, form.password)
}

#[derive(Deserialize)]
struct Pagination {
    page: usize,
    per_page: usize,
}
// 定义一个默认分页参数的结构体
impl Default for Pagination {
    fn default() -> Self {
        Self { page: 1, per_page: 30 }
    }
}
// 多个提取器可以同时使用，例如：
async fn get_user_things (
    Path(user_id): Path<Uuid>,
    pagination: Option<Query<Pagination>>,
) {
    let Query(pagination) = pagination.unwrap_or_default();

    // ...
}

//  访问请求的各个部分，如 headers 和 body
// 请求详细信息，eg. 请求方法、路径、查询参数、请求头、请求体等
pub async fn request(request: Request) -> ApiResponse<String> {
    // 访问请求头
    let headers = request.headers();
    println!("Request: {:?}", headers);
    // 访问请求体
    let body = request.body();
    println!("Body: {:?}", body);
    // 访问请求 URL
    let url = request.uri();
    println!("Url: {}", url);
    // 访问请求方法
    let method = request.method();
    println!("Method: {}", method);
    ApiResponse::new(StatusCode::OK.as_u16(), StatusCode::OK.to_string(), Some("request".to_string()))
}


/// 自定义响应类型
/*
axum 已经实现了多种响应，比如纯文本、HTML、JSON 及 自定义响应头(response header)。除了这些 axum 内置的响应之外，我们还将讨论如何将自己定义的结构体，作为响应返回给客户端。
axum 有句话说的是：
    Anything that implements IntoResponse can be returned from a handler
大意就是：凡是实现了 IntoResponse trait 的，都可作为 handler 的返回值，也就是我们所说的响应。
官方已经对若干常用数据类型实现了该 trait，亦是说，这些数据类型可以直接作为请求的响应进行返回。
对于我们自己的数据类型，比如自定义的 struct，也只需要实现 IntoResponse，就可以直接作为响应进行返回了。
*/

// 定义一个结构体来封装你的响应数据。这里我们定义一个 ApiResponse 结构体，它包含三个字段：status（状态码），message（消息）和 data（可选的数据）
#[derive(Debug, Serialize, Deserialize)]
pub struct ApiResponse<T> {
    pub status: u16,
    pub message: String,
    pub data: Option<T>,
}

// 自定义响应类型的实现
impl<T> ApiResponse<T> {
    fn new(status: u16, message: String, data: Option<T>) -> Self {
        Self {
            status,
            message,
            data,
        }
    }
}
// 为自定义响应类型 ApiResponse<T> 实现 IntoResponse trait，用于转换为 axum::response::Response 类型
impl<T> axum::response::IntoResponse for ApiResponse<T>
where
    T: serde::Serialize,
{
    // 实现 IntoResponse trait 的 into_response 方法，用于转换为 axum::response::Response 类型
    // 此处的 self 代表 ApiResponse<T> 结构体
    fn into_response(self) -> Response {
        let body = Json(&self);
        // 这里我们将自定义的结构体 ApiResponse<T> 转换为 JSON 格式的响应，并设置响应头 Content-Type: application/json
        (
            StatusCode::from_u16(self.status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR),
            body,
            // 这里我们设置响应头 Content-Type: application/json
        ).into_response()
    }
}

// axum 请求响应处理的官方文档： https://docs.rs/axum/latest/axum/response/index.html